package org.btik.light.mobile;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.btik.context.SimpleContext;
import org.btik.light.mobile.common.handler.nbi.NbiAgent;
import org.btik.light.mobile.discovery.ServerInfoPusher;
import org.btik.light.mobile.meta.MetaFactory;
import org.btik.light.mobile.meta.VideoChannelType;
import org.btik.light.mobile.meta.mo.DefaultDevMoFactory;
import org.btik.light.mobile.server.DevAccessServer;
import org.btik.light.mobile.databinding.ActivityMainBinding;
import org.btik.light.mobile.server.MsgCenter;
import org.btik.light.mobile.server.TimeOutCache;
import org.btik.light.mobile.server.entity.DevAccount;
import org.btik.light.mobile.ui.serial.controller.console.SerialConsoleThread;
import org.btik.light.tool.MDUtil;
import org.btik.video.server.device.udp2.MultiSegmentedFramesFrameVideoPainter;
import org.btik.video.server.device.udp2.OneFrameVideoPainter;
import org.btik.video.server.device.udp2.LHandleUDPDevChannel;
import org.btik.video.server.device.udp2.BufferPool;

import java.net.SocketException;

import static org.btik.light.mobile.platform.conf.AppConfig.LIGHT_SERVER_HOST;
import static org.btik.light.mobile.platform.conf.AppConfig.NAME_SPACE_LIGHT_HANDLER;
import static org.btik.light.mobile.platform.conf.ContextGlobalNames.*;
import static org.btik.light.tool.MDUtil.Algorithm.MD5;

public class MainActivity extends AppCompatActivity {

    private final Log log = LogFactory.getLog(MainActivity.class);
    private DevAccessServer devAccessServer;

    private LHandleUDPDevChannel deviceStreamChannel;

    private ActivityMainBinding binding;

    private static MainActivity mainActivity;


    private ServerInfoPusher serverInfoPusher;

    DefaultDevMoFactory devMoFactory;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainActivity = this;
        devMoFactory = new DefaultDevMoFactory();
        new MetaFactory(devMoFactory).load();
        startServices();
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home,
                R.id.serial_controller,
                R.id.navigation_notifications)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(binding.navView, navController);

        SharedPreferences sharedPreferences = getSharedPreferences(NAME_SPACE_LIGHT_HANDLER, Context.MODE_PRIVATE);
        String lightServerHost = sharedPreferences.getString(LIGHT_SERVER_HOST, "");
        SimpleContext.set(LIGHT_SERVER_HOST, lightServerHost);
    }

    private void startServices() {
        log.info("app start");
        devAccessServer = new DevAccessServer();
        devAccessServer.setPriority(7);
        devAccessServer.setAccessServerPort(8081);
        devAccessServer.setNonceTimeout(300000);
        TimeOutCache timeOutCache = new TimeOutCache();
        timeOutCache.start();
        devAccessServer.setTimeOutCache(timeOutCache);
        SimpleContext.set(DEV_MO_FACTORY, devMoFactory);
        defaultAccount();
        devAccessServer.setDevMoFactory(devMoFactory);
        devAccessServer.start();
        MsgCenter msgCenter = new MsgCenter();
        msgCenter.setDevAccessServer(devAccessServer);
        msgCenter.start();
        SimpleContext.set(MSG_CENTER, msgCenter);
        devAccessServer.setMsgCenter(msgCenter);
        deviceStreamChannel = createDeviceStreamChannel();
        try {
            NbiAgent.init();
        } catch (SocketException e) {
            Toast.makeText(this, R.string.nbi_agent_create_failed, Toast.LENGTH_SHORT).show();
        }
        createVideoServer();
        serverInfoPusher = new ServerInfoPusher();
        serverInfoPusher.setMulticastPort(8000);
        serverInfoPusher.setAsGatewayPort(8001);
        SimpleContext.set(SERVER_INFO_PUSHER, serverInfoPusher);
        serverInfoPusher.start();

        SerialConsoleThread serialConsoleThread = new SerialConsoleThread();
        serialConsoleThread.start();
        SimpleContext.set(SERIAL_CONSOLE_THREAD, serialConsoleThread);
    }

    private void defaultAccount() {
        DevAccount newDevAccount = new DevAccount();
        newDevAccount.setUsername("light");
        newDevAccount.setPasswd(MDUtil
                .digestAsHex(MD5, "light" + "light"));
        newDevAccount.setMdAlgorithm(MD5);
        SimpleContext.set(newDevAccount.getUsername(), newDevAccount);
    }

    private LHandleUDPDevChannel createDeviceStreamChannel() {
        LHandleUDPDevChannel udpDeviceChannel = new LHandleUDPDevChannel();
        SimpleContext.set(VIDEO_SERVER, udpDeviceChannel);
        udpDeviceChannel.setStreamPort(8004);
        BufferPool bufferPool = new BufferPool();
        bufferPool.setBufferPoolSize(500);
        udpDeviceChannel.setBufferPool(bufferPool);
        return udpDeviceChannel;
    }

    private void createVideoServer() {
        OneFrameVideoPainter videoChannel = new OneFrameVideoPainter();
        SimpleContext.set(VideoChannelType.ONE_FRAME_VIDEO_CHANNEL.getBeanId(), videoChannel);
        deviceStreamChannel.setVideoChannel(videoChannel);
        SimpleContext.set(VideoChannelType.MULTI_SEGMENTED_VIDEO_CHANNEL.getBeanId(),
                new MultiSegmentedFramesFrameVideoPainter());
        deviceStreamChannel.start();
    }

    public static void runUIWorker(Runnable runnable) {
        if (mainActivity == null) {
            return;
        }
        mainActivity.runOnUiThread(runnable);
    }

}